#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include <unistd.h>
#include <sys/time.h>
#include <semaphore.h>
#include <netinet/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/sockios.h>
#include <unistd.h>
#include <sys/time.h>
#include <semaphore.h>
#include <netinet/in.h>
#include <linux/tcp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <setjmp.h>
#include <errno.h>
#include "f_http_client.h"
#include "f_xg_typedef.h"


struct _FHttpClient{
	char* server_ip;
	int port;

	char* url;
	char* host;
	char* user_agent;
	char* content_type;
};

FHttpClient* f_http_client_create(const char* server_ip, int port){
	if(server_ip == NULL){
		return NULL;
	}

	FHttpClient* thiz = NULL;
	thiz = (FHttpClient*)malloc(sizeof(FHttpClient));
	if(thiz == NULL){
		return NULL;
	}

	thiz->server_ip = strdup(server_ip);
	thiz->port = port;

	thiz->url = NULL;
	thiz->host = NULL;
	thiz->user_agent = NULL;
	thiz->content_type = NULL;
	
	return thiz;
}

void f_http_client_destroy(FHttpClient* thiz){
	if(thiz){
		
		if(thiz->url){
			free(thiz->url);
		}
		if(thiz->host){
			free(thiz->host);
		}
		if(thiz->user_agent){
			free(thiz->user_agent);
		}
		if(thiz->content_type){
			free(thiz->content_type);
		}

		free(thiz);
		thiz = NULL;
	}
	
	return;
}

static int _send_data(int nSock,char *szBuff,int nLen){
    if(nSock < 0 || szBuff == NULL || !(nLen > 0)){
        return -1;
   	}	

    int nRetLen = 0;
    int nSendTotal = 0;
    while(nLen){
	    nRetLen = send(nSock, szBuff + nSendTotal, nLen, 0);
        nLen -= nRetLen;
        nSendTotal += nRetLen;
        if(nRetLen < 0){
            printf("send data  is error %d -------------------------\n",__LINE__);
			return -1;
        }
    }
    
    return 0;
}


static int _create_sock(void){
	int sock = -1;
    int 		nReuseAddr = 1;
    int		nFlag = 1;

	sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(sock == -1){
		printf("Error: create sock failed, error(%s)\n", strerror(errno));
		return -1;
	}

    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, ( void* )&nReuseAddr, sizeof( int ) );
    setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ( char* )&nFlag, sizeof( int ) );
	
	return sock;
}

static int _close_sock(int sock){
	return_val_if_fail(sock > 0, -1);

	shutdown(sock, 2);
	close(sock);

	return 0;
}


static int _parse_recv_buff(char* buff){
	return_val_if_fail(buff != NULL, -1);

	char* p = strstr(buff, "ret_code");
	if(p != NULL){
		int result = atoi((p + strlen("ret_code") + 2));
		return result;
	}

	return 0;
}

int f_http_client_post(FHttpClient* thiz, char* post_data, size_t post_data_len){
	int sock = -1;
    int nFlag;
	int	nRet;
    struct timeval          TimeOut;
	
	sock = _create_sock();
	
    nFlag = 1;
    setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ( void* )&nFlag, sizeof( int ) );
    TimeOut.tv_sec = 3;
    TimeOut.tv_usec = 0;
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, ( char* )&TimeOut, sizeof( TimeOut ) );
    TimeOut.tv_sec = 5;
    TimeOut.tv_usec = 0;
    setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, ( char* )&TimeOut, sizeof( TimeOut ) );
	
    struct sockaddr_in      daddr;
    bzero( &daddr, sizeof( struct sockaddr_in ) );
	daddr.sin_family        = AF_INET;
    daddr.sin_port          = htons(thiz->port);
    daddr.sin_addr.s_addr   = inet_addr(thiz->server_ip);
	
	nRet = connect(sock, ( struct sockaddr* )&daddr, sizeof( struct sockaddr ));
	if(nRet == -1){	//SOCKET_ERROR){
		perror("connect failed!\n");
        _close_sock(sock);
		return -1;
	}

	char request_buff[1024] = {0};

	sprintf(request_buff,
		"POST %s HTTP/1.1\r\n"
		"Host: %s\r\n"
		"User-Agent: %s\r\n"
		"Content-Type: %s\r\n"
		"Content-Length: %d\r\n\r\n"
		"%s\r\n\r\n",
		thiz->url, thiz->host, thiz->user_agent, thiz->content_type, post_data_len, post_data);

	printf("request_buff(%s) \n", request_buff);
	int request_len = strlen(request_buff);
	int ret = -1;
	ret = _send_data(sock, request_buff, request_len);
	if(ret == -1){ 	
		printf( "Error: send data failed!\n");
        _close_sock( sock );
		return -1;
	}
	
	char recv_buf[512] = {0};
    ret = recv(sock, recv_buf, 512, 0);
	if(ret > 0){
		printf("Result:%s\n", recv_buf);
		_close_sock(sock);
		return _parse_recv_buff(recv_buf);
	}
	else{
		printf("Error: recv failed, can't recv any data\n");
		_close_sock(sock);
		return -1;
	}
}


int f_http_client_set_url(FHttpClient* thiz, char* url){
	return_val_if_fail(thiz != NULL && url != NULL, -1);

	if(thiz->url != NULL){
		free(thiz->url);
		thiz->url = NULL;
	}

	thiz->url = strdup(url);

	return 0;
}

int f_http_client_set_host(FHttpClient* thiz, char* host){
	return_val_if_fail(thiz != NULL && host != NULL, -1);

	if(thiz->host != NULL){
		free(thiz->host);
		thiz->host = NULL;
	}

	thiz->host = strdup(host);

	return 0;
}

int f_http_client_set_user_agent(FHttpClient* thiz, char* user_agent){
	return_val_if_fail(thiz != NULL && user_agent != NULL, -1);

	if(thiz->user_agent != NULL){
		free(thiz->user_agent);
		thiz->user_agent = NULL;
	}

	thiz->user_agent = strdup(user_agent);

	return 0;
}

int f_http_client_set_content_type(FHttpClient* thiz, char* content_type){
	return_val_if_fail(thiz != NULL && content_type != NULL, -1);

	if(thiz->content_type != NULL){
		free(thiz->content_type);
		thiz->content_type = NULL;
	}

	thiz->content_type = strdup(content_type);

	return 0;
}


